package reflection;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * Created by : Infaraway
 * DATE : 2017/3/2
 * Time : 23:10
 * Funtion :
 */
public class testReflect {

    String className = "reflection.Student";

    /**
     * 测试反射的基本用法
     * @throws Exception
     */
    @Test
    public void testPerson() throws Exception {
        Class clazz = Class.forName("reflection.Person");

        // 1. Class类中的getFields，getMethods，getConstructors方法
        // 分别返回提供的public  域 方法 和构造器
        // 并且包括超类的公有成员
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }

        Method [] methods = clazz.getMethods();
        for (Method method: methods) {
            System.out.println(method.getName());
        }

        Constructor [] constructors = clazz.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName());
        }


        // 2. Class类中的getDeclaredFields，getDeclaredMethods，getDeclaredConstructors方法
        // 获取所有的方法包括private方法，且只获取当前类声明的方法
        // 不包括超类的成员
        Field[] fieldsDeclared = clazz.getDeclaredFields();
        for (Field field : fieldsDeclared) {
            System.out.println(field.getName());
        }


        Method [] methodsDeclared = clazz.getDeclaredMethods();
        for (Method method: methodsDeclared) {
            System.out.println("method2---"+method.getName());
        }

        Constructor [] constructorsDeclared = clazz.getDeclaredConstructors();
        for (Constructor constructor : constructorsDeclared) {
            System.out.println(constructor.getName());
        }


        // 3.获取指定的方法   getDeclaredMethod可以获取私有的方法
        // 获取特定方法时，需要两个东西确定调用的方法：1）方法名，2）方法的参数（重载）
        Method methodSp = clazz.getDeclaredMethod("setName",String.class);
        System.out.println(methodSp);

        //当需要使用反射式，参数类型必须是包装类  int --> Integer 等等
        Method methodSp2 = clazz.getDeclaredMethod("setName",String.class, Integer.class);
        System.out.println(methodSp2);

        //4. 执行方法
        Object object = clazz.newInstance();
        methodSp.invoke(object, "zhong");



    }

    /**
     * 获取方法
     * @throws Exception
     */
    @Test
    public void testStudentMethod() throws Exception {
        Class clazz = Class.forName("reflection.Student");
        Method method1 = ReflectUtils.getMethod(clazz,"studentMethod", "xidian");
        System.out.println(method1);
        Method method2 = ReflectUtils.getMethod(clazz, "personMethod");
        System.out.println(method2);
    }

    /**
     * 调用方法测试
     * @throws Exception
     */
    @Test
    public void testInvokeMethod() throws Exception{
        //Class clazz = Class.forName("reflection.Student");
        Object obj = new Student();
        ReflectUtils.invokeMethod(obj, "studentMethod", "xidian");
        ReflectUtils.invokeMethod(obj, "personMethod");
    }

    /**
     * 测试字段  属性
     */
    @Test
    public void testField() throws Exception{
        Class clazz = Class.forName(className);

        //获取全部属性的值  公有私有 getField 和getDeclaredField
        Field [] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }

        Student student = new Student("zhong", 22);

        //获取特定的属性
        Field field = clazz.getField("name");
        //特定属性的get和set方法
        System.out.println(field.get(student));
        field.set(student, "Tom");
        System.out.println(field.get(student));

        Field [] field2 = clazz.getDeclaredFields();
        for (Field field1 : field2) {
            System.out.println(field1.getName());
        }
    }
}
